package com.jair.jairaiagent.app;

import com.jair.jairaiagent.advisor.MyLoggerAdvisor;
import com.jair.jairaiagent.chatMemory.DatabaseChatMemory;
import com.jair.jairaiagent.chatMemory.FileBasedChatMemory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Component
@Slf4j
public class LoveApp {

    private final ChatClient chatClient;
    private String SYSTEM_PROMPT_PLUS;

    @Autowired
    @Qualifier("loveAppVectorStore")
    private VectorStore loveAppVectorStore;

    @Autowired
    @Qualifier("loveAppRagCloudAdvisor")
    private Advisor loveAppRagCloudAdvisor;

    @Autowired
    @Qualifier("pgVectorVectorStore")
    private VectorStore pgVectorVectorStore;

    // 合并构造函数，确保所有依赖一次性注入
    @Autowired
    public LoveApp(
            ChatModel dashscopeChatModel,
//            DatabaseChatMemory databaseChatMemory,
            @Value("classpath:/prompts/system-message.st") Resource systemResource) {

        //基于资源文件的对话记忆
        String dir = System.getProperty("user.dir")+"/chat-memory";
        //ChatMemory chatMemory = new FileBasedChatMemory(dir);

        // 验证系统提示模板资源
        if (systemResource == null) {
            throw new IllegalArgumentException("系统提示模板资源注入失败，为null");
        }

        try {
            if (!systemResource.exists()) {
                throw new IOException("系统提示模板文件不存在: " + systemResource.getDescription());
            }

            // 正确初始化系统提示模板
            SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
            this.SYSTEM_PROMPT_PLUS = systemPromptTemplate.create().toString();
            log.info("系统提示模板加载成功");
        } catch (IOException e) {
            log.error("加载系统提示模板失败", e);
            // 使用默认系统提示词作为备选
            this.SYSTEM_PROMPT_PLUS = "扮演深耕恋爱心理领域的专家。开场向用户表明身份，告知用户可倾诉恋爱难题。" +
                    "围绕单身、恋爱、已婚三种状态提问：单身状态询问社交圈拓展及追求心仪对象的困扰；" +
                    "恋爱状态询问沟通、习惯差异引发的矛盾；已婚状态询问家庭责任与亲属关系处理的问题。" +
                    "引导用户详述事情经过、对方反应及自身想法，以便给出专属解决方案。";
        }

        // 初始化聊天客户端
        chatClient = ChatClient.builder(dashscopeChatModel)
                .defaultSystem(SYSTEM_PROMPT_PLUS)
                .defaultAdvisors(
                        // 基于内存的对话记忆
                        new MessageChatMemoryAdvisor(new InMemoryChatMemory())
                        //基于资源文件的持久化对话记忆
//                        new MessageChatMemoryAdvisor(new FileBasedChatMemory(dir))
                        // 基于MySQ来进行一个持久化对话记忆
//                        new MessageChatMemoryAdvisor(databaseChatMemory)
                        //基于PgVector进行一个持久化对话记忆 TODO

                        // 日志
//                        new MyLoggerAdvisor()
                )
                .build();
    }


    /**
     * Ai聊天，利用内存存储/文件存储/Mysql存储对话实现支持多轮对话
     * @param message
     * @return
     */
    public String doChat(String message,String chatId) {
        log.info("用户输入：{}", message);
        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .chatResponse();

        String text = null;
        if (chatResponse != null) {
            text = chatResponse.getResult().getOutput().getText();
        }
        log.info("Ai输出：{}", text);
        return text;
    }

    record LoveReport(String title, List<String> suggestions) {
    }

    /**
     * Ai聊天，利用内存存储对话实现支持多轮对话  结构化输出
     * @param message
     * @return
     */
    public LoveReport doChatWithJson(String message,String chatId) {
        log.info("用户输入：{}", message);
        LoveReport loveReport = chatClient.prompt()
                .system(SYSTEM_PROMPT_PLUS +"每次对话后生成 title为（用户名）的恋爱报告，和建议列表")
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .call()
                .entity(LoveReport.class);

        return loveReport;
    }

    /**
     * 基于RAG检索增强的Ai定制化聊天
     */
    public String doChatWithRag(String message,String chatId) {
        log.info("用户输入：{}", message);
        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))     //配置对话记忆参数
//                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))  // 用Advisors和本地SpringAi内置向量数据库来实现RAG检索增强
//                .advisors(loveAppRagCloudAdvisor)  //使用云端RAG检索增强
                .advisors(new QuestionAnswerAdvisor(pgVectorVectorStore))  //使用PGSQL数据库的数据量加载到向量数据库然后进行操作来实现RAG检索增强
                .call()
                .chatResponse();

        String text = null;
        if (chatResponse != null) {
            text = chatResponse.getResult().getOutput().getText();
        }
        log.info("Ai输出：{}", text);
        return text;
    }



}
